今天做了一個TodoList程式當作練習,
首先看到有兩個外部元件, Button元件 和 ListItem元件:
Button.js
import React from 'react'
const Button = (props) => {
//呼叫的是由上層元件從props.onButtonClick傳入的方法
return <button onClick={props.onButtonClick}>{props.text}</button>
}
export default Button
先看 Button 這個元件,點擊 Button 時觸發 onclick 方法,裡面是
{props.onButtonClick}
按了它等於呼叫上層元件(父元件)中的方法 onButtonClick,是一個上層元件中的方法定義。
ListItem.js
import React from 'react'
const ListItem = (props) => {
//呼叫的是由上層元件從props.onItemClick傳入的方法
return <li onClick={props.onItemClick}>{props.text}</li>
}
export default ListItem
ListItem元件 跟 Button 差不多,只是點擊 list 的項目觸發 onclick 後,呼叫的是上層元件中的 onItemClick 方法。
onButtonClick 跟 onItemClick 都是函式類型的值,它是在上層元件中設定給它的。在 Button 跟 ListItem 中, onClick 事件觸發時,並不是呼叫自己元件中的方法,而是去呼叫到父元件中定義的方法。
接下來是今天最主要的 TodoList 元件:
TodoList.js
import React, { Component } from 'react'
import ListItem from './ListItem'
import Button from './Button'
class TodoList extends React.Component {
constructor(props) {
super(props)
this.state = {
items: [],
inputValue: '',
}
}
//下面還有程式碼...
import 要用到的項目,使用 constructor 建構 state 的初始值, 有 items:空陣列 和 inputValue:空字串
handleChange = (e) => {
this.setState({ inputValue: e.target.value })
}
handleAddItem = () => {
const newItems = [this.state.inputValue, ...this.state.items]
//按下Button後,加到列表項目中並清空輸入框
this.setState({
items: newItems,
inputValue: '',
})
}
handleKeyDown = (e) => {
if (e.key === 'Enter') {
const newItems = [this.state.inputValue, ...this.state.items]
//按下鍵盤Enter後,加到列表項目中並清空輸入框
this.setState({
items: newItems,
inputValue: '',
})
}
}
//處理過濾掉其中一個陣列成員的方法
handleRemoveItem = (id) => {
const newItems = this.state.items.filter((item, i) => i !== id)
//整個陣列重新更新
this.setState({
items: newItems,
})
}
//下面還有程式碼...
handleChange 是處理文字輸入框在輸入文字時做出改變用的
handleAddItem 是Button被按下時處理的方法,獲取到 inputValue 的值,然後把新的項目加到陣列中,最後把文字輸入框中的文字清空,所以設定 state 中的 inputValue 值為空字串
handleKeyDown 是輸入框被按下 Enter 鍵時處理的方法,獲取到的 KeyboardEvent 物件的 key 屬性,判斷按下的是Enter鍵,然後把新的項目加到陣列中,按下 Enter 鍵時,也要把文字輸入框中的文字清空,所以也要設定 state 中的 inputValue 值為空字串
handleRemoveItem 並不是給這個元件(TodoList)使用的,而是給包含在其中的子項目元件(ListItem)使用的,當 list 中的項目被點按時,使用 filter 過濾掉這筆資料,再用 setState 更新 items 陣列
render() {
return (
<div>
<input
type="text"
value={this.state.inputValue}
placeholder={"請輸入文字"}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
/>
<Button text="新增項目" onButtonClick={this.handleAddItem}></Button>
<ul>
{
this.state.items.map((value, id) => {
return <ListItem key={value} text={value} onItemClick={() => this.handleRemoveItem(id)} />
})
}
</ul>
</div>
)
}
}
export default TodoList
render() 的部分,相較於之前的 TextInput元件,在文字輸入框的地方,多了一個onKeyDown的事件,它是用來獲取按下鍵盤時的事件用的,觸發 handleKeyDown 方法。
而在下面的是加入了一個 Button ,作用和按下 Enter 鍵差不多,都是新增 List 的項目,只是透過點擊外部元件 Button 去觸發 handleAddItem 方法。
最後<ul>標籤裡面加入了一個使用陣列的map方法,把所有目前的在state 中的 items 項目整個輸出。
這邊有個 key 值,是用於像這種 List 項目,或是有多個同樣的元件在 React 中渲染時使用的,它並不是 props 的成員,而是讓 React 用於識別不同的元件(或DOM元素)使用的。React會要求像這種列表項目時,一定要給key值。
List 項目被點按時觸發 handleRemoveItem 方法,用 id 傳遞了點選項目的索引值,給 handleRemoveItem 裡面使用 filter 過濾掉該筆資料。
執行結果:
在文字輸入框輸入文字後按下 Button 或是 鍵盤Enter鍵,就會把文字加到下面的列表中,每個項目用滑鼠點按一下,會觸發這個項目的刪除